package com.netty.server;

import com.netty.server.handler.PersonServerHandler;
import com.netty.server.handler.MessageServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author xurongbei
 */
public class NettyServer {

    /**
     * 监听线程组，监听客户端请求
     */
    private EventLoopGroup parentGroup = null;
    /**
     * 处理客户端相关操作线程组，负责处理与客户端的数据通讯
     */
    private EventLoopGroup childGroup = null;
    /**
     * 服务端启动相关配置
     */
    private ServerBootstrap bootstrap = null;

    public NettyServer() {
        init();
    }

    private void init(){
        parentGroup = new NioEventLoopGroup();
        childGroup = new NioEventLoopGroup();
        bootstrap = new ServerBootstrap();
        //绑定线程组
        bootstrap.group(parentGroup,childGroup);
        //设置通讯模式为NIO
        bootstrap.channel(NioServerSocketChannel.class);
        //设置缓冲区大小
        bootstrap.option(ChannelOption.SO_BACKLOG,1024);
        //SO_SNDBUF为发送缓冲区
        bootstrap.option(ChannelOption.SO_SNDBUF, 16*1024);
        //SO_RCVBUF为接受缓冲区，
        bootstrap.option(ChannelOption.SO_RCVBUF, 16*1024);
        //，SO_KEEPALIVE表示心跳检测，保证连接有效
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

    }

    /**
     * childHandler是bootstrap独有的方法，是用于提供处理对象的
     * 可以一次性处理若干个请求，类似责任连模式的处理方式
     * 增加A.B离鞥个处理线程，在处理的时候按照顺序先运行A再运行B
     *
     * ChannelInitializer用于提供处理器的一个模拟对象
     * 其中定义了initChannel方法
     * 用于初始化逻辑责任链条的
     * 可以保证服务器的bootstrap只被初始化一次
     * @param port
     * @param acceptHandlers
     * @return
     * @throws InterruptedException
     */
    public ChannelFuture doAccept(int port, final ChannelHandler ...acceptHandlers) throws InterruptedException {
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(acceptHandlers);
            }
        });

        ChannelFuture future = bootstrap.bind(port).sync();
        return future;
    }

    public void release(){
        this.parentGroup.shutdownGracefully();
        this.childGroup.shutdownGracefully();
    }

    public static void main(String[] args) throws InterruptedException {
        ChannelFuture future=null;
        NettyServer nettyServer = null;
        try {
            nettyServer = new NettyServer();
            future = nettyServer.doAccept(9999, new MessageServerHandler(),new PersonServerHandler());
            System.out.println("server started:");

            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null != future) {
                try{
                    future.channel().closeFuture().sync();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
            if(null != nettyServer)
            {
                nettyServer.release();
            }
        }

    }
}
